from pathlib import Path
from typing import Dict, List, Optional
import random
import os
import sys
import json
import logging
import shutil

# 添加项目根目录到Python路径
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, project_root)

from config.word_banks import (
    WORD_BANKS_CONFIG,
    DIFFICULTY_LEVELS,
    WORD_BANK_TAGS
)

class WordBank:
    def __init__(self):
        self.words = []
        self.current_bank = "default"
        
        # 获取 typing_game 项目的根目录
        current_file = os.path.abspath(__file__)  # 当前文件路径
        src_dir = os.path.dirname(current_file)   # src 目录
        project_dir = os.path.dirname(src_dir)    # typing_game 目录
        
        # 设置词库目录路径
        self.word_banks_dir = os.path.join(project_dir, "data", "word_banks")
        logging.info(f"词库目录: {self.word_banks_dir}")
        
        # 确保词库目录存在
        if not os.path.exists(self.word_banks_dir):
            logging.error(f"词库目录不存在: {self.word_banks_dir}")
            logging.info("尝试创建词库目录...")
            try:
                os.makedirs(self.word_banks_dir, exist_ok=True)
            except Exception as e:
                logging.error(f"创建词库目录失败: {str(e)}")
        
    def validate_word_bank(self, words: List[Dict]) -> bool:
        """验证词库格式是否正确"""
        if not isinstance(words, list):
            logging.error("词库数据不是列表格式")
            return False
        
        for word_item in words:
            if not isinstance(word_item, dict):
                logging.error("词库中存在非字典格式的单词")
                return False
            
            # 检查必需字段 - 适配您的词库格式
            if "word" not in word_item:
                logging.error("单词缺少 word 字段")
                return False
            
            # 检查 word 字段
            if not isinstance(word_item["word"], str) or not word_item["word"].strip():
                logging.error("word 字段格式错误")
                return False
            
            # 其他字段可选，但如果存在则检查类型
            if "pos" in word_item and not isinstance(word_item["pos"], str):
                logging.error("pos 字段格式错误")
                return False
            
            if "definition" in word_item and not isinstance(word_item["definition"], str):
                logging.error("definition 字段格式错误")
                return False
            
            if "meaning" in word_item and not isinstance(word_item["meaning"], str):
                logging.error("meaning 字段格式错误")
                return False
        
        return True

    def check_and_convert_word_bank(self, file_path: str) -> bool:
        """检查并转换词库格式"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
                
            # 检查是否需要转换
            needs_conversion = False
            words_data = None
            
            if isinstance(data, dict) and "words" in data:
                words_data = data["words"]
            elif isinstance(data, list):
                words_data = data
                needs_conversion = True
                
            if words_data is None:
                logging.error(f"词库格式无效: {file_path}")
                return False
                
            # 检查并转换单词格式
            new_words = []
            for word_item in words_data:
                if isinstance(word_item, str):
                    # 字符串格式转换为字典格式
                    new_words.append({
                        "word": word_item,
                        "pos": "未知",
                        "definition": "暂无释义",
                        "type": "word",
                        "difficulty": 1
                    })
                elif isinstance(word_item, dict):
                    # 保持原有格式
                    new_words.append(word_item)
                else:
                    logging.error(f"无效的单词格式: {word_item}")
                    return False
                    
            if needs_conversion:
                # 备份原文件
                backup_path = file_path + '.backup'
                shutil.copy2(file_path, backup_path)
                logging.info(f"已备份原词库文件到: {backup_path}")
                
                # 保存新格式
                with open(file_path, 'w', encoding='utf-8') as f:
                    json.dump({"words": new_words}, f, ensure_ascii=False, indent=2)
                logging.info(f"已将词库 {file_path} 转换为新格式")
                
            return True
            
        except Exception as e:
            logging.error(f"检查/转换词库格式失败: {str(e)}")
            return False

    def load_word_bank(self, bank_name: str) -> bool:
        """加载指定的词库"""
        try:
            file_path = os.path.join(self.word_banks_dir, f"{bank_name}.json")
            logging.info(f"尝试加载词库文件: {file_path}")
            
            if not os.path.exists(file_path):
                logging.error(f"词库文件不存在: {file_path}")
                return False
                
            # 读取词库文件
            with open(file_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
                
            # 获取单词列表
            if isinstance(data, dict) and "words" in data:
                words_data = data["words"]
            else:
                words_data = data
                
            # 验证单词列表
            if not isinstance(words_data, list):
                logging.error(f"词库格式错误: 预期单词列表，实际是 {type(words_data)}")
                return False
                
            # 打印单词数量和示例
            logging.info(f"词库 {bank_name} 包含 {len(words_data)} 个单词")
            if words_data:
                logging.info(f"第一个单词示例: {words_data[0]}")
                
            # 验证每个单词的格式
            for word_item in words_data:
                if not isinstance(word_item, dict):
                    logging.error(f"单词格式错误: {word_item}")
                    return False
                if "word" not in word_item:
                    logging.error(f"单词缺少 word 字段: {word_item}")
                    return False
                
            self.words = words_data
            self.current_bank = bank_name
            logging.info(f"成功加载词库 {bank_name}，共 {len(self.words)} 个单词")
            return True
            
        except Exception as e:
            logging.error(f"加载词库 {bank_name} 失败: {str(e)}")
            logging.error(f"文件路径: {file_path}")
            logging.error(f"错误详情: {str(e)}")
            return False

    def get_words(self, count: int = 10) -> List[Dict]:
        """
        获取指定数量的练习单词
        
        Args:
            count: 需要的单词数量
            
        Returns:
            List[Dict]: 单词信息列表
        """
        if not self.words:
            logging.warning("当前词库为空")
            return []
            
        # 如果词库单词数量小于请求数量，返回所有单词的随机排序
        if len(self.words) <= count:
            return random.sample(self.words, len(self.words))
        else:
            # 从词库中随机选择指定数量的单词
            selected_words = random.sample(self.words, count)
            logging.info(f"从词库中随机选择了 {len(selected_words)} 个单词")
            return selected_words
        
    def create_default_word_bank(self) -> None:
        """创建默认词库"""
        default_words = [
            {
                "word": "hello",
                "pos": "int.",
                "meaning": "你好，打招呼用语",
                "example": "Hello, how are you?"
            },
            {
                "word": "world",
                "pos": "n.",
                "meaning": "世界，地球",
                "example": "Hello, world!"
            },
            {
                "word": "python",
                "pos": "n.",
                "meaning": "Python编程语言",
                "example": "Python is easy to learn."
            },
            {
                "word": "programming",
                "pos": "n.",
                "meaning": "编程，程序设计",
                "example": "I love programming."
            },
            {
                "word": "practice",
                "pos": "n./v.",
                "meaning": "练习，实践",
                "example": "Practice makes perfect."
            }
        ]
        
        try:
            file_path = os.path.join(self.word_banks_dir, "default.json")
            if not os.path.exists(file_path):
                with open(file_path, 'w', encoding='utf-8') as f:
                    json.dump(default_words, f, ensure_ascii=False, indent=2)
                logging.info("成功创建默认词库")
        except Exception as e:
            logging.error(f"创建默认词库失败: {str(e)}")

    def set_word_bank(self, bank_id: str) -> bool:
        """设置当前词库"""
        # 检查词库是否存在
        file_path = os.path.join(self.word_banks_dir, f"{bank_id}.json")
        if not os.path.exists(file_path):
            logging.error(f"词库不存在: {bank_id}")
            return False
        
        # 尝试加载词库
        if self.load_word_bank(bank_id):
            self.current_bank = bank_id
            logging.info(f"已切换到词库: {bank_id}")
            return True
        
        return False
    
    def get_bank_info(self, bank_id: str = None) -> dict:
        """获取词库信息"""
        if bank_id is None:
            bank_id = self.current_bank
        
        # 如果找不到配置信息，返回一个默认配置
        default_info = {
            'name': bank_id,  # 使用词库ID作为默认名称
            'difficulty': 1,
            'tags': [],
            'description': ''
        }
        
        try:
            return WORD_BANKS_CONFIG.get(bank_id, default_info)
        except Exception as e:
            logging.error(f"获取词库信息失败: {str(e)}")
            return default_info
    
    def get_recommended_wpm(self, bank_id: str = None) -> int:
        """获取推荐打字速度"""
        bank_info = self.get_bank_info(bank_id)
        return bank_info['recommended_wpm'] if bank_info else 30
    
    def get_difficulty_level(self, bank_id: str = None) -> str:
        """获取难度等级描述"""
        bank_info = self.get_bank_info(bank_id)
        if bank_info:
            level_num = bank_info['difficulty']
            return DIFFICULTY_LEVELS.get(level_num, '未知难度')
        return '未知难度'
    
    def get_tags(self, bank_id: str = None) -> List[str]:
        """获取词库标签"""
        bank_info = self.get_bank_info(bank_id)
        return bank_info['tags'] if bank_info else []
    
    def get_description(self, bank_id: str = None) -> str:
        """获取词库描述"""
        bank_info = self.get_bank_info(bank_id)
        return bank_info['description'] if bank_info else '无描述'

    def import_word_bank(self, file_path: str, bank_name: str = None) -> bool:
        """
        导入词库文件
        
        Args:
            file_path: 要导入的词库文件路径
            bank_name: 导入后的词库名称，如果为None则使用文件名
            
        Returns:
            bool: 是否导入成功
        """
        try:
            # 验证源文件
            if not os.path.exists(file_path):
                logging.error(f"要导入的文件不存在: {file_path}")
                return False
                
            # 读取并验证词库内容
            with open(file_path, 'r', encoding='utf-8') as f:
                words = json.load(f)
                if not self.validate_word_bank(words):
                    logging.error(f"导入文件格式错误: {file_path}")
                    return False
            
            # 确定目标词库名称
            if bank_name is None:
                bank_name = Path(file_path).stem
                
            # 复制到词库目录
            target_path = os.path.join(self.word_banks_dir, f"{bank_name}.json")
            shutil.copy2(file_path, target_path)
            
            logging.info(f"成功导入词库 {bank_name}，共 {len(words)} 个单词")
            return True
            
        except Exception as e:
            logging.error(f"导入词库失败: {str(e)}")
            return False
            
    def export_word_bank(self, bank_name: str, target_path: str) -> bool:
        """
        导出词库文件
        
        Args:
            bank_name: 要导出的词库名称
            target_path: 导出目标路径
            
        Returns:
            bool: 是否导出成功
        """
        try:
            # 检查源词库是否存在
            source_path = os.path.join(self.word_banks_dir, f"{bank_name}.json")
            if not os.path.exists(source_path):
                logging.error(f"要导出的词库不存在: {bank_name}")
                return False
                
            # 确保目标目录存在
            os.makedirs(os.path.dirname(target_path), exist_ok=True)
            
            # 复制文件
            shutil.copy2(source_path, target_path)
            
            logging.info(f"成功导出词库 {bank_name} 到 {target_path}")
            return True
            
        except Exception as e:
            logging.error(f"导出词库失败: {str(e)}")
            return False
            
    def list_word_banks(self) -> List[str]:
        """列出所有可用的词库"""
        try:
            # 确保使用正确的词库目录路径
            if not os.path.exists(self.word_banks_dir):
                logging.error(f"词库目录不存在: {self.word_banks_dir}")
                return []

            banks = []
            logging.info(f"正在扫描词库目录: {self.word_banks_dir}")
            for file in os.listdir(self.word_banks_dir):
                if file.endswith('.json'):
                    bank_name = os.path.splitext(file)[0]
                    banks.append(bank_name)
                    logging.info(f"找到词库文件: {file}")

            # 按名称排序，确保中文文件名也能正确排序
            banks.sort()
            logging.info(f"所有可用词库: {banks}")
            return banks
        except Exception as e:
            logging.error(f"获取词库列表失败: {str(e)}")
            return []

    def validate_word_bank_file(self, file_path: str) -> bool:
        """
        验证词库文件格式
        
        Args:
            file_path: 词库文件路径
            
        Returns:
            bool: 是否为有效的词库文件
        """
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
                
            # 基本格式验证
            if not isinstance(data, list):
                logging.error("词库必须是单词列表格式")
                return False
                
            # 内容验证
            for word in data:
                if not isinstance(word, str) or not word.strip():
                    logging.error("词库中包含无效单词")
                    return False
                    
            # 大小验证
            if len(data) < 10:
                logging.warning("词库单词数量过少")
                return False
                
            return True
            
        except json.JSONDecodeError:
            logging.error("词库文件不是有效的JSON格式")
            return False
        except Exception as e:
            logging.error(f"验证词库文件失败: {str(e)}")
            return False

    def initialize_word_banks(self) -> None:
        """初始化词库系统"""
        try:
            # 确保词库目录存在
            os.makedirs(self.word_banks_dir, exist_ok=True)
            
            # 检查现有词库
            existing_banks = self.list_word_banks()
            logging.info(f"发现现有词库: {existing_banks}")
            
            # 检查每个词库的内容
            for bank_name in existing_banks:
                file_path = os.path.join(self.word_banks_dir, f"{bank_name}.json")
                logging.info(f"检查词库文件: {file_path}")
                with open(file_path, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    if "words" in data:
                        words = data["words"]
                        logging.info(f"词库 {bank_name} 包含 {len(words)} 个单词")
            
            # 如果没有任何词库，创建默认词库
            if not existing_banks:
                self.create_default_word_bank()
            
        except Exception as e:
            logging.error(f"初始化词库系统失败: {str(e)}")

    def inspect_word_bank(self, bank_name: str) -> None:
        """检查词库文件的内容"""
        try:
            file_path = os.path.join(self.word_banks_dir, f"{bank_name}.json")
            with open(file_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
                
            logging.info(f"\n词库 {bank_name} 内容检查:")
            logging.info(f"文件路径: {file_path}")
            logging.info(f"数据类型: {type(data)}")
            
            if isinstance(data, dict):
                logging.info(f"包含的键: {list(data.keys())}")
                if "words" in data:
                    words = data["words"]
                    logging.info(f"单词列表类型: {type(words)}")
                    logging.info(f"单词总数: {len(words)}")
                    logging.info("前10个单词示例:")
                    for i, word in enumerate(words[:10]):
                        logging.info(f"  {i+1}. {word}")
                    logging.info(f"完整的词库内容:")
                    logging.info(json.dumps(data, ensure_ascii=False, indent=2))
            else:
                logging.info(f"数据内容: {data}")
                
        except Exception as e:
            logging.error(f"检查词库失败: {str(e)}")

    def fix_word_bank_file(self, file_path: str) -> bool:
        """修复词库文件格式"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read().strip()
                
            # 如果文件以 "words": [ 开头，添加缺失的 {
            if content.startswith('"words":'):
                content = '{' + content + '}'
                
            # 尝试解析
            data = json.loads(content)
            
            # 保存修复后的文件
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
                
            logging.info(f"成功修复词库文件: {file_path}")
            return True
            
        except Exception as e:
            logging.error(f"修复词库文件失败 {file_path}: {str(e)}")
            return False
